using System;
using System.Collections.Generic;
using System.Text;
using Framework;
using Framework.Physics;
using Framework.MyMath;
using Microsoft.DirectX.Direct3D;
using System.Drawing;
using Microsoft.DirectX;
using System.Windows.Forms;
using Framework.Fonts;
using PhysicsTest.Dice;

namespace PhysicsTest
{
    class DiceView : GameLayer
    {
        Mesh tableMesh;
        Material tableMaterial;
        Texture tableTexture;
        Mesh diceMesh;
        Material diceMaterial;
        Texture diceTexture;


        const float DiceMeshSize = 4f;


        //TexturedBox m_box;
        TexturedBox m_flippedBox;

        //int m_numSpheres = 1;
        bool m_pressed = false;

        float m_radius = 5;

        int nframe = 0;


        bool m_useShaders = true;
        Effect m_effect;


        Dice.DiceSimulation diceSimulation = new PhysicsTest.Dice.DiceSimulation();


        float m_camSpeed = 0.004f;
        Camera m_camera;

        public DiceView()
            : base()
        {
            //CollisionDetectorWC wcdetector = new CollisionDetectorWC(m_simulator);

            //CollisionMesh mesh = CollisionMesh.FromFile(DefaultValues.MediaPath + "ring1.cm", false);
            //this.m_simulator.CollisionDetector = wcdetector;
            
            //m_simulator.DoAngularDrag = true;
            //m_simulator.DoLinearDrag = true;
            isTransparent = false;

            //CollidableBoxCon con = new CollidableBoxCon(new MyVector(0, 0, 0), 10);
            //m_objects.Add(new CollidableSphere(new MyVector(0f, 20f, 0f), 6));
            //m_objects.Add(new CollidableSphere(new MyVector(0, 0, 0), 3));
            //m_objects.Add(new CollidableSphere(new MyVector(20, 0, 20), 3));
            //m_objects.Add(new CollidableSphere(new MyVector(-20, 0, 20), 3));

            //nSpheres = 4;

            ////m_objects.Add(new CollidablePlane(new MyVector(0, -35, 0), new MyVector(1, 1, 0).Normalize()));
            ////m_objects.Add(new CollidablePlane(new MyVector(0, -35, 0), new MyVector(-1, 1, 0).Normalize()));
            //m_objects.Add(con.PhysicalObject);
            //m_objects.Add(new Dice(new MyVector(0, 0, 0)));
            //m_objects.Add(new Dice(new MyVector(20, 0, 0)));
            ////m_objects.Add(new CollidablePlane(new MyVector(0,-35,0),new MyVector(0,1,0)));
            ////m_objects.Add(new CollidableBox(new MyVector(0, -30, 0), 10, false));

            ////m_objects[4].Type = ObjectType.Still;
            //m_objects[4].Type = ObjectType.Static;
            ////m_objects[4].AngularVelocity = new MyVector(0, 0, 1f);
            ////m_objects[5].Type = ObjectType.Static;
            ////m_objects[5].Type = ObjectType.Static;
            ////m_objects[0].Position = new MyVector(0, 0, 0);
            ////m_objects[1].Position = new MyVector(-20.5f, 10f, 0);
            ////m_objects[0].Velocity = new MyVector(10, 0, -10);
            ////m_objects[1].Velocity = new MyVector(-10, 0, 0);
            //m_objects[2].Velocity = new MyVector(-10, 0, -10);
            //m_objects[3].Velocity = new MyVector(10, 0, -10);
            ////m_objects[5].Velocity = new MyVector(15, 0, -1);
            ////RigidBodyData data = m_objects[5].RigidBody;
            //m_objects[5].Orientation = MyQuaternion.FromEulerAngles(0, (float)Math.PI / 4, (float)Math.PI / 3);
            //m_objects[5].Velocity = new MyVector(40, 10, -10);

            //m_objects[6].Orientation = MyQuaternion.FromEulerAngles(0, (float)Math.PI / 5, (float)Math.PI / 5);
            //m_objects[6].Velocity = new MyVector(-55, 40, -24);
            ////m_objects[5].RigidBody = data;
            ////m_objects[0].Velocity.Y = -1.5f;
            ////m_objects[1].Velocity.X = -12;

            //m_simulator.AddObject(m_objects[0]);
            ////m_simulator.AddObject(m_objects[1]);
            ////m_simulator.AddObject(m_objects[2]);
            ////m_simulator.AddObject(m_objects[3]);
            ////m_simulator.AddObject(m_objects[4]);
            //wcdetector.AddConstrainingObject(con);
            //wcdetector.RemoveObject(con.PhysicalObject);
            ////m_simulator.AddObject(m_objects[5]);
            ////m_simulator.AddObject(m_objects[6]);

            ////m_objects.Add(new CollidableSphere(new MyVector(0, -20, 0), 7));
            ////m_objects.Add(new CollidableBox(new MyVector(1f, 0, 0), 15,false));

            ////m_objects[0].Type = ObjectType.Still;
            ////m_simulator.AddObject(m_objects[0]);
            ////m_simulator.AddObject(m_objects[1]);
            ////box

            diceSimulation.StartSimulation(0);
            diceSimulation.PhysicsSimulator.Paused = true;
            diceSimulation.PhysicsSimulator.DoGravity = true;
            //m_simulator.Paused = true;
        }


        public override void OnCreateDevice(Device device)
        {
            base.OnCreateDevice(device);
            m_flippedBox = new TexturedBox(device, m_radius / (float)Math.Sqrt(2), 20, true, Color.White);

            m_camera = new Camera();
            m_camera.LookV = new Vector3(0, 0, -1);
            m_camera.PositionV = new Vector3(0, 0, 70);
            m_camera.InvertY = false;
            m_camera.MaxVelocity = 20;

            GM.AppWindow.CenterCursor();
            GM.AppWindow.AddKeyLock(Keys.Left);
            GM.AppWindow.AddKeyLock(Keys.Right);
            GM.AppWindow.AddKeyLock(Keys.Up);
            GM.AppWindow.AddKeyLock(Keys.Down);

            if (m_useShaders)
            {
                string path = "..\\..\\..\\media\\myshader.fx";

                string errors;
                m_effect = Effect.FromFile(device, path, null, null, ShaderFlags.PartialPrecision, null, out errors);

            }

        }
        public override void OnResetDevice(Device device)
        {
            base.OnResetDevice(device);
            ExtendedMaterial[] ext = new ExtendedMaterial[1];
            diceMesh = Mesh.FromFile(DefaultValues.MediaPath + "dice.x", MeshFlags.Managed, device, out ext);


            diceMaterial = ext[0].Material3D;
            diceMaterial.Ambient = Color.FromArgb(0, 30, 30, 30);
            diceTexture = TextureLoader.FromFile(device, DefaultValues.MediaPath + "dice.jpg");

            diceMesh.ComputeNormals();

            tableMesh = Mesh.FromFile(DefaultValues.MediaPath + "diceTable.x", MeshFlags.Managed, device, out ext);
            tableMaterial = ext[0].Material3D;

            //device.RenderState.ShadeMode = ShadeMode.Gouraud;
            device.RenderState.FillMode = FillMode.Solid;
            device.SamplerState[0].MagFilter = TextureFilter.Linear;
            device.SamplerState[0].MinFilter = TextureFilter.Linear;
            device.SamplerState[0].MaxAnisotropy = 0;
            device.SamplerState[0].MipFilter = TextureFilter.Linear;


            device.Lights[0].Diffuse = Color.White;
            device.Lights[0].Ambient = Color.FromArgb(0, 30, 30, 30);
            device.Lights[0].Type = LightType.Point;
            //device.Lights[0].Direction = new Vector3(0, 0, -1);
            device.Lights[0].Position = new Vector3(0, 25, 25);
            device.Lights[0].Range = 1000f;
            device.Lights[0].Attenuation0 = 0.0f;

            device.Lights[0].Update();
            device.Lights[0].Enabled = true;

        }
        public override void OnLostDevice(Device device)
        {
            base.OnLostDevice(device);
        }
        public override void OnDestroyDevice(Device device)
        {
            base.OnDestroyDevice(device);

        }
        public override void OnUpdateFrame(Device device, float elapsedTime)
        {
            base.OnUpdateFrame(device, elapsedTime);
            //m_simulator.AdvanceSimulation(0.0011f); 
            //timeSinceLastSFrame += elapsedTime;
            //if (timeSinceLastSFrame > simulationFrameTime)
            //{
            //    m_simulator.AdvanceSimulation(simulationFrameTime);
            //    timeSinceLastSFrame -= simulationFrameTime;
            //    if (m_simulator.Paused == false)
            //        nframe++;

            //    bool status = true;
            //    foreach (IPhysicalObject s in m_simulator.Objects)
            //    {
            //        if (s.Velocity.LengthSq < 0.3f && s.Position.Y < -29.8f)
            //        {
            //            s.Type = ObjectType.Static;
            //            s.Velocity = new MyVector(0, 0, 0);
            //            s.AngularVelocity = new MyVector(0, 0, 0);
            //        }
            //        else
            //        {
            //            status = false;
            //        }
            //    }
            //    if (status)
            //    {
            //        m_simulator.Paused = true;
            //    }
            //}
            diceSimulation.UpdateSimulation(elapsedTime);

            m_camera.Update(elapsedTime);



        }
        public override void OnRenderFrame(Device device, float elapsedTime)
        {
            base.OnRenderFrame(device, elapsedTime);


            // Set render states
            device.SetRenderState(RenderStates.ZBufferWriteEnable, true);
            device.SetRenderState(RenderStates.ZEnable, true);
            device.SetRenderState(RenderStates.Lighting, true);
            device.SetRenderState(RenderStates.AlphaBlendEnable, false);
            device.RenderState.CullMode = Cull.Clockwise;
            device.Transform.View = m_camera.View;

            //dice1
            IPhysicalObject s = diceSimulation.Dices[0];
            float scale = DiceSimulation.DiceSize / DiceMeshSize;

            device.Transform.World = Matrix.Scaling(scale, scale, scale) * Matrix.RotationQuaternion((Quaternion)s.Orientation)
                * Matrix.Translation((Vector3)s.Position);
            device.Material = diceMaterial;
            device.SetTexture(0, diceTexture);

            if (m_useShaders)
            {
                m_effect.SetValue("worldViewProj", device.Transform.World * device.Transform.View * device.Transform.Projection);
                m_effect.SetValue("world", device.Transform.World);
                m_effect.SetValue("m_Texture", diceTexture);
                m_effect.SetValue("lightColor", device.Lights[0].DiffuseColor);
                m_effect.SetValue("ambientColor", device.Lights[0].AmbientColor);
                Vector4 lightPos = new Vector4(device.Lights[0].Position.X, device.Lights[0].Position.Y, device.Lights[0].Position.Z, 1);
                m_effect.SetValue("lightPos", lightPos);
                m_effect.Technique = "RenderWithLight";
                m_effect.Begin(0);
                m_effect.BeginPass(0);
            }
            diceMesh.DrawSubset(0);
            if (m_useShaders)
            {
                m_effect.EndPass();
                m_effect.End();
            }
            device.SetTexture(0, null);
            

            //dice2
            s = diceSimulation.Dices[1];
            device.Transform.World = Matrix.Scaling(scale, scale, scale) * Matrix.RotationQuaternion((Quaternion)s.Orientation)
                * Matrix.Translation((Vector3)s.Position);
            device.Material = diceMaterial;
            device.SetTexture(0, diceTexture);

            if (m_useShaders)
            {
                m_effect.SetValue("worldViewProj", device.Transform.World * device.Transform.View * device.Transform.Projection);
                m_effect.SetValue("world", device.Transform.World);
                m_effect.SetValue("m_Texture", diceTexture);
                m_effect.SetValue("lightColor", device.Lights[0].DiffuseColor);
                m_effect.SetValue("ambientColor", device.Lights[0].AmbientColor);
                Vector4 lightPos = new Vector4(device.Lights[0].Position.X, device.Lights[0].Position.Y, device.Lights[0].Position.Z, 1);
                m_effect.SetValue("lightPos", lightPos);
                m_effect.Technique = "RenderWithLight";
                m_effect.Begin(0);
                m_effect.BeginPass(0);
            }
            diceMesh.DrawSubset(0);
            if (m_useShaders)
            {
                m_effect.EndPass();
                m_effect.End();
            }
            device.SetTexture(0, null);

            //table
            scale = (float)(m_radius / Math.Sqrt(2));

//            device.Transform.World = Matrix.Scaling(DiceSimulation.TableWidth / scale, 2*DiceSimulation.TableDepth / scale, DiceSimulation.TableLength/scale);
            device.Transform.World = Matrix.Identity;

            device.Material = tableMaterial;
            device.SetTexture(0, diceTexture);

            if (m_useShaders)
            {
                m_effect.SetValue("worldViewProj", device.Transform.World * device.Transform.View * device.Transform.Projection);
                m_effect.SetValue("world", device.Transform.World);
                m_effect.SetValue("m_Texture", tableTexture);
                m_effect.SetValue("lightColor", device.Lights[0].DiffuseColor);
                m_effect.SetValue("ambientColor", device.Lights[0].AmbientColor);
                Vector4 lightPos = new Vector4(device.Lights[0].Position.X, device.Lights[0].Position.Y, device.Lights[0].Position.Z, 1);
                m_effect.SetValue("lightPos", lightPos);
                m_effect.Technique = "RenderWithLight";
                m_effect.Begin(0);
                m_effect.BeginPass(0);
            }
            tableMesh.DrawSubset(0);
            if (m_useShaders)
            {
                m_effect.EndPass();
                m_effect.End();
            }
            device.SetTexture(0, null);
            //m_flippedBox.Draw(device, World);


            //device.Transform.World = Matrix.RotationQuaternion((Quaternion)s.Orientation)
            //    * Matrix.Translation((Vector3)s.Position);
            //device.Material = m_sphereMaterial;
            //device.SetTexture(0, m_sphereTexture);

            //if (m_useShaders)
            //{
            //    m_effect.SetValue("worldViewProj", device.Transform.World * device.Transform.View * device.Transform.Projection);
            //    m_effect.SetValue("world", device.Transform.World);
            //    m_effect.SetValue("m_Texture", m_sphereTexture);
            //    m_effect.SetValue("lightColor", device.Lights[0].DiffuseColor);
            //    m_effect.SetValue("ambientColor", device.Lights[0].AmbientColor);
            //    Vector4 lightPos = new Vector4(device.Lights[0].Position.X, device.Lights[0].Position.Y, device.Lights[0].Position.Z, 1);
            //    m_effect.SetValue("lightPos", lightPos);
            //    m_effect.Technique = "RenderWithLight";
            //    m_effect.Begin(0);
            //    m_effect.BeginPass(0);
            //}
            //m_sphereMesh.DrawSubset(0);
            //if (m_useShaders)
            //{
            //    m_effect.EndPass();
            //    m_effect.End();
            //}
            //device.SetTexture(0, null);



            device.RenderState.CullMode = Cull.CounterClockwise;
            StringBlock b = new StringBlock("Linear Drag: " + this.diceSimulation.PhysicsSimulator.DoLinearDrag.ToString() +
                "\nAngular Drag:" + diceSimulation.PhysicsSimulator.DoAngularDrag.ToString() +
                "\nGravity:" + diceSimulation.PhysicsSimulator.DoGravity.ToString() +
                "\nnFrame:" + nframe.ToString(), new RectangleF(10, 50, 300, 150), new RectangleF(10, 50, 300, 150), Align.Left, 20, ColorValue.FromColor(Color.White), true);
            List<Quad> quads = GM.FontManager.GetDefaultFamily().GetFont(DefaultValues.TextSize).GetProcessedQuads(b);
            GM.FontManager.GetDefaultFamily().GetFont(DefaultValues.TextSize).Render(device, quads);
        }


        public override void OnKeyboard(List<System.Windows.Forms.Keys> pressedKeys, List<System.Windows.Forms.Keys> releasedKeys, char pressedChar, int pressedKey, float elapsedTime)
        {
            base.OnKeyboard(pressedKeys, releasedKeys, pressedChar, pressedKey, elapsedTime);
            switch (pressedKey)
            {
                case (int)Keys.R:
                    diceSimulation.PhysicsSimulator.DoLinearDrag = !diceSimulation.PhysicsSimulator.DoLinearDrag;
                    break;
                case (int)Keys.F:
                    diceSimulation.PhysicsSimulator.DoAngularDrag = !diceSimulation.PhysicsSimulator.DoAngularDrag;
                    break;
                case (int)Keys.G:
                    diceSimulation.PhysicsSimulator.DoGravity = !diceSimulation.PhysicsSimulator.DoGravity;
                    break;
                case (int)Keys.P:
                    diceSimulation.PhysicsSimulator.Paused = !diceSimulation.PhysicsSimulator.Paused;
                    break;

                case (int)Keys.A:
                    m_camera.StrafeSpeed(-25f);
                    break;
                case (int)Keys.D:
                    m_camera.StrafeSpeed(25f);
                    break;
                case (int)Keys.W:
                    m_camera.UpSpeed(25);
                    break;
                case (int)Keys.S:
                    m_camera.UpSpeed(-25);
                    break;
                case (int)Keys.Z:
                    m_camera.Accelerate(0.05f);
                    break;
                case (int)Keys.X:
                    m_camera.Accelerate(-0.05f);
                    break;
                case (int)Keys.Q:
                    m_camera.Roll(-0.05f);
                    break;
                case (int)Keys.E:
                    m_camera.Roll(0.05f);
                    break;
            }
            foreach (Keys k in releasedKeys)
            {
                switch (k)
                {
                    case Keys.A:
                        m_camera.StrafeSpeed(0);
                        break;
                    case Keys.D:
                        m_camera.StrafeSpeed(0);
                        break;
                    case Keys.W:
                        m_camera.UpSpeed(0);
                        break;
                    case Keys.S:
                        m_camera.UpSpeed(0);
                        break;
                    case Keys.Q:
                        m_camera.Roll(0);
                        break;
                    case Keys.E:
                        m_camera.Roll(0);
                        break;

                }
            }
        }

        public override void OnMouse(Point position, int xDelta, int yDelta, int zDelta, bool[] pressed,
            bool[] released, float elapsedTime)
        {
            base.OnMouse(position, xDelta, yDelta, zDelta, pressed, released, elapsedTime);
            m_camera.Pitch((float)-yDelta * m_camSpeed);
            m_camera.Yaw((float)-xDelta * m_camSpeed);
            GM.AppWindow.CenterCursor();


            if (released[0] || released[2])
                m_pressed = false;
        }




    }
}
